package com.teamin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.mysql.cj.core.util.StringUtils;
import com.teamin.dto.UploadFIle;
import com.teamin.dto.UploadFIleListDTO;
import com.teamin.entity.FileEntity;
import com.teamin.entity.FileTempEntity;
import com.teamin.entity.NetDisk;
import com.teamin.entity.OSSSTSEntity;
import com.teamin.mapper.CircleMapper;
import com.teamin.mapper.FileMapper;
import com.teamin.mapper.NetDiskMapper;
import com.teamin.service.FileService;
import com.teamin.service.INetDiskService;
import com.teamin.service.impl.oss.OSSSTSUtilas;
import com.teamin.utils.Utils;
import com.teamin.web.Evn;
import io.swagger.models.auth.In;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class FileServiceImpl implements FileService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    FileMapper fileMapper;

    @Autowired
    NetDiskMapper netDiskMapper;

    @Autowired
    CircleMapper circleMapper;


    @Autowired
    INetDiskService iNetDiskService;

    public FileServiceImpl() {

    }

    /**
     * 获取PUT 方式上传文件的URL
     *
     * @param key
     * @return
     */
    private String getFileUrl(String key) {
        Date expiration = new Date(System.currentTimeMillis() + Evn.ALIYUN_OSS_EXPIRES);
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(Evn.ALIYUN_OSS_BUCKENAME, key, HttpMethod.PUT);
        request.setExpiration(expiration);
        OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
        URL signedUrl = client.generatePresignedUrl(request);
        return signedUrl.toString();
    }

    /**
     * 获取一个向圈子中上传文件的URL
     *
     * @param taskId 任务ID
     * @return URL
     * @fileName 文件名
     */
    @Override
    public JSONObject getTaskPostUrl(Long userId, Long taskId, String fileName, Long fileSize) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");

        int inc = fileMapper.insertTempFile(uuid, FILE_STROAGE_TYPE_TASK, taskId, fileName, Utils.getFileSuffixName(fileName));
        /*将评论中的图片同步到网盘中*/
        NetDisk netDisk = new NetDisk();
        netDisk.setCircleid(Integer.valueOf(circleMapper.selectOnlyCircleIdByTask(taskId) + ""));
        netDisk.setIsFile(1);
        netDisk.setFileName(fileName);
        netDisk.setParentId(-1L);
        netDisk.setUuid(uuid);
        netDisk.setFileSize(fileSize);
        netDisk.setSuffix(Utils.getFileSuffixName(fileName));
        netDisk.setCreateUserid(userId);
        netDiskMapper.save(netDisk);
        /*将评论中的图片同步到网盘中*/
        if (inc > 0) {
            FileEntity fileEntity = new FileEntity();
            fileEntity.setUuid(uuid);
            /*fileEntity.setUrl(
            )*/
            ;
            JSONObject resu = postObject(uuid, fileSize);
            resu.put("uuid", uuid);
            logger.info(resu.toString());
            return resu;
        }
        return null;
    }

    /**
     * @Author: yangrui
     * @Description: 获取一个向网盘中上传文件的URL
     * @Date: 下午5:35 2017/11/21
     */
    public JSONObject getNetDiskPostUrl(Long loginUserId, Integer fkCircleId, Long folderId, String fileName, Long fileSize) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");

        NetDisk netDisk = new NetDisk();
        netDisk.setCircleid(fkCircleId);
        netDisk.setIsFile(1);
        netDisk.setParentId(folderId);
        netDisk.setFileName(fileName);
        netDisk.setSuffix(Utils.getFileSuffixName(fileName));
        netDisk.setUuid(uuid);
        netDisk.setFileSize(fileSize);
        netDisk.setCreateUserid(loginUserId);
        netDisk.setIsdelete(2);
        boolean aBoolean = iNetDiskService.save(netDisk);
        if (aBoolean) {
            FileEntity fileEntity = new FileEntity();
            fileEntity.setUuid(uuid);
            /*fileEntity.setUrl(
            )*/
            ;
            JSONObject resu = postObject(uuid, fileSize);
            resu.put("uuid", uuid);
            logger.info(resu.toString());
            return resu;
        }
        return null;
    }

    /**
     * 采用OSS子帐号来操作文件
     *
     * @param key
     * @return
     */
    public OSSSTSEntity getOssSubAuthor(String key) {
        OSSSTSUtilas ossstsUtilas = new OSSSTSUtilas();
        AssumeRoleResponse oss = ossstsUtilas.getTempToken();
        OSSSTSEntity osst = new OSSSTSEntity();
        osst.setToken(oss.getCredentials().getSecurityToken());
        osst.setAccessKey(oss.getCredentials().getAccessKeyId());
        osst.setAccessSecurity(oss.getCredentials().getAccessKeySecret());
        osst.setFileKey(key);
        return osst;
    }

    /**
     * 采用POST 方式上传文件
     *
     * @param key
     * @param size
     * @return
     * @throws Exception
     */
    @Override
    public JSONObject postObject(String key, Long size) {
        JSONObject formFields = new JSONObject();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");//注意格式化的表达式
        String date = format.format(new Date(System.currentTimeMillis() + Evn.ALIYUN_OSS_EXPIRES)) + "Z";
        formFields.put("key", key);
        formFields.put("OSSAccessKeyId", Evn.ALIYUN_OSS_KEYID);
        String policy = "{\"expiration\": \"" + date + "\",\"conditions\": [ {\"bucket\": \"" + Evn.ALIYUN_OSS_BUCKENAME + "\" }, [\"eq\", \"$key\", \"" + key + "\"],[\"content-length-range\", " + 0 + ", " + IMGE_SIZE_LIMIT + "]]}";
        System.out.println(policy);
        // policy
        String encodePolicy = new String(Base64.encodeBase64(policy.getBytes()));
        formFields.put("policy", encodePolicy);
        // Signature
        String signaturecom = computeSignature(Evn.ALIYUM_OSS_KEYSECRET, encodePolicy);
        formFields.put("Signature", signaturecom);

        formFields.put("url", "https://" + Evn.ALIYUN_OSS_BUCKENAME + "." + Evn.ALIYUN_OSS_ENDPOINT.substring(Evn.ALIYUN_OSS_ENDPOINT.indexOf("oss")));
        System.out.println(formFields.toJSONString());
        return formFields;
    }

    /**
     * 计算签名 POST
     *
     * @param accessKeySecret
     * @param encodePolicy
     * @return
     * @throws UnsupportedEncodingException
     */
    String computeSignature(String accessKeySecret, String encodePolicy) {
        // convert to UTF-8
        try {
            byte[] key = accessKeySecret.getBytes("UTF-8");
            byte[] data = encodePolicy.getBytes("UTF-8");
            // hmac-sha1
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(new SecretKeySpec(key, "HmacSHA1"));
            byte[] sha = mac.doFinal(data);
            // base64
            return new String(Base64.encodeBase64(sha));
        } catch (Exception ignore) {

        }
        return null;
    }

    /**
     * 获取文件大小
     *
     * @param key 文件路径
     * @return
     */
    public Long getFileSize(String key) {
        OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
        ObjectMetadata metadata = client.getObjectMetadata(Evn.ALIYUN_OSS_BUCKENAME, key);
        logger.info("getFileSize" + metadata);
        return metadata.getContentLength();
    }


    /**
     * 查询临时文件属性
     *
     * @return 插入的状态
     * @uuid UUID
     */
    public FileTempEntity selectTempFile(String uuid) {
        return fileMapper.selectTempFile(uuid);
    }

    /**
     * 删除临时文件
     *
     * @return 插入的状态
     * @uuid UUID
     */
    public int deleteTempFile(String uuid) {
        return fileMapper.deleteTempFile(uuid);
    }

    /**
     * 插入一个文件
     *
     * @return 插入的状态
     * @uuid UUID
     */
    public int insertFile(FileEntity file) {
        return fileMapper.insertFile(file);
    }

    /**
     * 检查是否支持此格式的缩略图
     *
     * @param format 指定的格式
     * @return
     */
    public boolean supportThumbnailFormat(String format) {
        if (StringUtils.isNullOrEmpty(format))
            return false;
        return suportThumbnail.contains(format.toLowerCase());
    }

    /**
     * 获取文件在OSS上的缩略图的URL
     *
     * @param uuid
     * @param fileName 文件名
     * @return
     * @throws UnsupportedEncodingException
     */
    public String getFileUrl(String uuid, String fileName) {
        Date expiration = new Date(System.currentTimeMillis() + Evn.ALIYUN_OSS_EXPIRES);
        String key = null;
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(Evn.ALIYUN_OSS_BUCKENAME, uuid, HttpMethod.GET);
        if (!StringUtils.isNullOrEmpty(fileName)) {
            String fileNameUrl = null;
            try {
                fileNameUrl = URLEncoder.encode(fileName, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            request.addQueryParameter("response-content-disposition", "attachment;filename=" + fileNameUrl + ";filename*=UTF-8''" + fileNameUrl);
        }
        request.setExpiration(expiration);
        OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
        URL signedUrl = client.generatePresignedUrl(request);
        return signedUrl.toString();
    }

    /**
     * 获取文件在OSS上的缩略图的URL
     *
     * @param uuid
     * @param fileName 文件名
     * @return
     * @throws UnsupportedEncodingException
     */
    public String getFileThumbnail(String uuid, String fileName) {

        Date expiration = new Date(System.currentTimeMillis() + Evn.ALIYUN_OSS_EXPIRES);
        String key = null;
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(Evn.ALIYUN_OSS_BUCKENAME, uuid, HttpMethod.GET);
        if (!StringUtils.isNullOrEmpty(fileName)) {
            String fileNameUrl = null;
            try {
                fileNameUrl = URLEncoder.encode(fileName, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            request.addQueryParameter("response-content-disposition", "inline;filename=" + fileNameUrl + ";filename*=UTF-8''" + fileNameUrl);
            request.addQueryParameter("x-oss-process", "image/resize,m_lfit,h_" + 530 + ",w_" + 377);
        }
        request.setExpiration(expiration);
        OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
        URL signedUrl = client.generatePresignedUrl(request);
        return signedUrl.toString();
    }

    /**
     * 删除OSS 上面的文件
     *
     * @param key
     */
    public void deleteFileByOSS(String key) {
        List<String> lf = new ArrayList<>();
        lf.add(key);
        OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
        DeleteObjectsResult deleteObjectsResult = client.deleteObjects(new DeleteObjectsRequest(Evn.ALIYUN_OSS_BUCKENAME).withKeys(lf));
        deleteObjectsResult.getDeletedObjects();
    }

    /**
     * 回收临时文件
     */
    public void recoveryTempFile() {
        List<FileTempEntity> li = fileMapper.getRecoveryTempFile();
        List<String> lf = new ArrayList<>();
        for (FileTempEntity l : li) {
            lf.add(l.getUuid());
        }

        if (lf.size() != 0) {
            OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
            DeleteObjectsResult deleteObjectsResult = client.deleteObjects(new DeleteObjectsRequest(Evn.ALIYUN_OSS_BUCKENAME).withKeys(lf));
            deleteObjectsResult.getDeletedObjects();
        }
    }

    /**
     * 回收已被删除文件
     */
    @Override
    public void recoveryDeleteFile() {
        List<FileEntity> li = fileMapper.selectDeletedFile();
        Map<String, Integer> map = new HashMap<>();
        List<String> lf = new ArrayList<>();
        for (FileEntity l : li) {
            lf.add(l.getUuid());
            map.put(l.getUuid(), l.getId());
        }

        if (lf.size() != 0) {
            OSSClient client = new OSSClient(Evn.ALIYUN_OSS_ENDPOINT, Evn.ALIYUN_OSS_KEYID, Evn.ALIYUM_OSS_KEYSECRET);
            DeleteObjectsResult deleteObjectsResult = client.deleteObjects(new DeleteObjectsRequest(Evn.ALIYUN_OSS_BUCKENAME).withKeys(lf));

            List<String> obs = deleteObjectsResult.getDeletedObjects();

            StringBuffer sb = new StringBuffer();
            if (obs != null) {
                for (String s : obs) {
                    sb.append("," + map.get(s));
                }
            }

            if (!StringUtils.isNullOrEmpty(sb.toString())) {
                //设删除的文件
                updateRecovery(sb.toString());
            }
        }
    }

    /**
     * 设置文件删除状态,设置后会在指定时间内自动清除OSS 上面的文件
     */
    @Override
    public int deleteFile(Long fileId) {
        return fileMapper.deleteFile(fileId);
    }

    /**
     * 获取已被删除的文件删除文件
     */
    @Override
    public List<FileEntity> selectDeletedFile() {
        return fileMapper.selectDeletedFile();
    }

    /**
     * 设置文件删除状态,设置后会在指定时间内自动清除OSS 上面的文件
     */
    @Override
    public int updateRecovery(String fileIds) {
        return fileMapper.updateRecovery(fileIds);
    }

    @Override
    public int deleteFileByUUID(String uuid) {
        return fileMapper.deleteFileByUUID(uuid);
    }

    @Override
    public FileEntity getById(Integer id) {
        return this.fileMapper.selectByPrimaryKey(id);
    }

    /**
     * 保持上传文件，同时获取OSS上传地址
     *
     * @param loginUserId
     * @param fkCircleId
     * @param uploadFIleListDTO
     */
    /*public void saveFile(Long loginUserId, Integer fkCircleId, UploadFIleListDTO uploadFIleListDTO) {

        for (UploadFIle upfile : uploadFIleListDTO.getUploadFIles()) {
            JSONObject uploadData = this.getNetDiskPostUrl(loginUserId, fkCircleId, uploadFIleListDTO.getFolderId(), upfile.getFileName(), upfile.getFileSize());
            upfile.setUploadData(uploadData);
        }

    }*/
}
